/******************************************************
Compile : gcc -O3 -o infer-random infer-random.c enhance-sim.c utils.c solver.c -lm
******************************************************/

#include "solver.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void print_help ()
{
	printf ("Usage		: ./infer-random model N L mode A M random_seed\n");
	printf ("		 (./infer-random 0 11 12 0 41 10000 $RANDOM)\n\n");
	printf ("model		: 0 SIM; 1 SIM + Reliable Trans; 2 SIM + Convergence; 3 SIM + Reliable Trans + Convergence\n\n");
	printf ("N		: number of nodes\n");
	printf ("L		: number of steps\n");
	printf ("mode		: 0: set '0'; 1: set '1'; 2: set randomly\n");
	printf ("A		: number of presetted elements\n");
	printf ("M		: number of tries\n");
	printf ("random_seed	: random seed\n");
}

int do_infer (int model, int N, int L, int pathway[L][N])
{
	int i, j, m, flag;

	int S[L][N]; /* state variable */
	int g[N][N], r[N][N]; /* network variable ; g[i][j]/r[i][j] edge from j to i */

	for (i = 0; i < L; i++)
	{
		for (j = 0; j < N; j++)
		{
			S[i][j] = i * N + j;
		}
	}

	for (i = 0; i < N; i++)
	{
		for (j = 0; j < N; j++)
		{
			g[i][j] = L * N + i * N + j;
			r[i][j] = L * N + N * N + i * N + j;
		}
	}

	solver *s, *s2;
	bool st;

	s = solver_new ();

	m = 2 * N * N + L * N;

	/* restriction of the strong inhibition rules */
	m = sim_model (N, L, pathway, S, g, r, s, m);

	if (model == 1)
	{
		m = reliable_trans (N, 0, L, S, g, r, s, m);
	}
	else if (model >= 2)
	{
		if (model == 3)
		{
			/* restriction of the quickflips */
			forbidden_quickflips (0, N, L, S, s);
		}
		m = convergence (N, 0, L, S, g, r, s, m);
	}

	/* forbidden all '0'/'1' node in the pathway */
	forbidden_noflip (N, L, S, s);

	/* setup the known values in the pathway */
	set_pathway (N, L, pathway, S, s);

	/* setup fix point */
	set_fixpoint (N, L, S, s);

	/* prevent early fixpoint */
	m = prevent_early_fixpoint (N, L, S, s, m);

	st = solver_simplify (s);
	if (st == true)
		st = solver_solve (s,0,0);

	if (st == true)
	{
		flag = 1;

		for (i = 0; i < L; i++)
		{
			for (j = 0; j < N; j++)
			{
				if (pathway[i][j] == -1)
				{
					if (s->model.ptr[S[i][j]] == l_True)
						pathway[i][j] = 1;
					else
						pathway[i][j] = 0;
				}
			}
		}
	}
	else
		flag = 0;

	solver_delete (s);

	return flag;
}

void print_pathway (int N, int L, int pathway[L][N])
{
	int i, j;

	for (i = 0; i < L; i++)
	{
		for (j = 0; j < N; j++)
		{
			if (pathway[i][j] == -1)
				printf ("* ");
			else
				printf ("%d ", pathway[i][j]);
		}
		printf ("\n");
	}
}

void generate_pathway (int N, int L, int mode, int A, int pathway[L][N])
{
	int i, j;

	for (i = 0; i < L; i++)
	{
		for (j = 0; j < N; j++)
		{
			pathway[i][j] = -1;
		}
	}

	int x, y;

	for (i = 0; i < A; i++)
	{
		do
		{
			x = drand48 () * (L - 1);
			y = drand48 () * N;
		} while (pathway[x][y] != -1);
		if (mode == 2)
			pathway[x][y] = drand48() * 2;
		else
			pathway[x][y] = mode;
	}
}

int main (int argc, char *argv[])
{
	long int seed;
	int i, j, k, n, flag;
	int model, mode, N, L, A, M;

	if (argc == 1)
	{
		print_help ();
		exit (0);
	}

	model = atoi (argv[1]);
	N = atoi (argv[2]);
	L = atoi (argv[3]);
	mode = atoi (argv[4]);
	A = atoi (argv[5]);
	M = atoi (argv[6]);
	seed = atoi (argv[7]);
	srand48 (seed);

	int pathway[L][N];

	n = 0;
	for (i = 0; i < M; i++)
	{
		generate_pathway (N, L, mode, A, pathway);

		for (j = 0; j < N; j++)
		{
			flag = 0;
			for (k = 0; k < L - 1; k++)
			{
				flag += pathway[k][j];
			}
			if (flag == 0 || flag == L - 1)
				break;
		}

		//print_pathway (N, L, pathway);
		if (flag == 0 || flag == L - 1)
			flag = 0;
		else
			flag = do_infer (model, N, L, pathway);
		if (flag == 1)
		{
			n ++;
			printf ("c candidate pathway\n");
			print_pathway (N, L, pathway);
			//printf ("Pass\n");
		}
		//else
			//printf ("Fail\n");
	}
	printf ("Feasibility : %5d / %5d ( N = %2d, L = %2d, A = %3d )\n", n, M, N, L, A);
}
